﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vibz.Game.Bugs.Model;
using System.Drawing;
using System.Windows.Forms;
using Vibz.Common.Sequential;
using Vibz.Common;

namespace Vibz.Game.Bugs
{
    internal class GroundObjectInstance
    {
        Vibz.Game.Bugs.Model.Orientation previousOrientation;
        public Vibz.Game.Bugs.Model.Orientation PreviousOrientation
        {
            get
            {
                if (this.Data.GetType().GetInterfaces().Contains(typeof(IMovingObject)))
                {
                    previousOrientation = ((IMovingObject)this.Data).PreviousOrientation;
                }
                if (previousOrientation == null)
                    previousOrientation = new Model.Orientation(this.Data, this.Body, MoveDirection.Up);
                return previousOrientation;
            }
        }
        Rectangle _body;
        public Rectangle Body
        {
            get { return _body; }
            set
            {
                this.PreviousOrientation.Rectangle = _body;
                if (this.Data.GetType().GetInterfaces().Contains(typeof(IMovingObject)))
                {
                    ((IMovingObject)this.Data).PreviousOrientation = new Model.Orientation(this.Data, _body, ((IMovingObject)this.Data).Direction);
                    if ((IMovingObject)((IElement)this.Data).Previous != null)
                        ((IMovingObject)this.Data).Direction = ((IMovingObject)((IElement)this.Data).Previous).PreviousOrientation.Direction;
                }
                if (!_body.Equals(value))
                {
                    _body = value;
                    Data.Location = _body.Location;
                    RequiresRedraw = true;
                }
            }
        }
        public bool IsActive { get; set; }
        public virtual GroundObject Data { get; set; }
        public int FontSize { get { return (Data.Thickness / 10) * 5; } }
        public GroundObjectInstanceList Owner { get; set; }
        public bool RequiresRedraw { get; set; }

        public GroundObjectInstance(GroundObjectInstanceList owner, GroundObject obj)
        {
            this.IsActive = true;
            this.Owner = owner;
            this.Data = obj;
            this.Body = new Rectangle(obj.Location.X, obj.Location.Y, obj.Thickness, obj.Thickness);
        }
        public override string ToString()
        {
            return "Instance of " + Data.GetType().Name + ":" + Data.ID.ToString();
        }
        public void Display(Control container, PaintEventArgs e)
        {
            switch (this.Data.GetType().Name)
            {
                case "Power":
                    e.Graphics.DrawImage(GetPowerImage(((Power)this.Data).Type), this.Body);
                    break;
                case "Coin":
                    e.Graphics.DrawImage(Properties.Resources.fast, this.Body);
                    break;
                case "Obstacle":
                    e.Graphics.DrawImage(Properties.Resources.slow, this.Body);
                    break;
                case "Compartment":
                    Bitmap b = new Bitmap(Properties.Resources.ant, this.Body.Size);
                    b = RotateImage(b, Orientation);
                    e.Graphics.DrawImage(b, this.Body.Location);
                    //e.Graphics.DrawString(((IMovingObject)this.Data).Direction.ToString()[0].ToString(),
                    //    new Font(FontFamily.GenericSerif, 8), new SolidBrush(Color.Blue), this.Body);
                    break;
                case "Player":
                    b = new Bitmap(Properties.Resources.bug1, this.Body.Size);
                    b = RotateImage(b, Orientation);
                    e.Graphics.DrawImage(b, this.Body.Location);
                    break;
            }
        }
        private Bitmap RotateImage(Bitmap b, float angle)
        {
            Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
            Graphics g = Graphics.FromImage(returnBitmap);
            g.TranslateTransform((float)b.Width / 2, (float)b.Height / 2);
            g.RotateTransform(angle);
            g.TranslateTransform(-(float)b.Width / 2, -(float)b.Height / 2);
            g.DrawImage(b, new Point(0, 0));
            return returnBitmap;
        }


        public void Revoke()
        {
            switch (this.Data.GetType().Name)
            {
                case "Power":
                case "Coin":
                case "Obstacle":
                    this.Owner.Remove(this);
                    this.IsActive = false;
                    break;
                case "Compartment":
                    break;
                case "Player":
                    break;
            }
            this.RequiresRedraw = true;
        }
        public Color Color
        {
            get
            {
                switch (this.Data.GetType().Name)
                {
                    case "Power":
                        return Color.Yellow;
                    case "Coin":
                        return Color.Green;
                    case "Obstacle":
                        return Color.Red;
                    case "Compartment":
                        return Color.Gray;
                    case "Player":
                        return Color.Blue;
                }
                return Color.Black;
            }
        }
        public float Orientation
        {
            get
            {
                switch (((IMovingObject)this.Data).Direction)
                {
                    case MoveDirection.Up:
                        return 0.0F;
                    case MoveDirection.UpRight:
                        return 45.0F;
                    case MoveDirection.Right:
                        return 90.0F;
                    case MoveDirection.DownRight:
                        return 135.0F;
                    case MoveDirection.Down:
                        return 180.0F;
                    case MoveDirection.DownLeft:
                        return 225.0F;
                    case MoveDirection.Left:
                        return 270.0F;
                    case MoveDirection.UpLeft:
                        return 315.0F;
                }
                return 0.0F;
            }
        }
        public Image GetPowerImage(PowerType pType)
        {
            switch (pType)
            {
                case PowerType.CrossEdge:
                    return Properties.Resources.power1;
                case PowerType.DriveDiogonal:
                    return Properties.Resources.power4;
            }
            return Properties.Resources.power4;
        }
    }
    internal class GroundObjectInstanceList : List<GroundObjectInstance>
    {
        public new void Add(GroundObjectInstance gi)
        {
            gi.RequiresRedraw = true;
            base.Add(gi);
        }
        public GroundObjectInstance AddUpdate(GroundObject obj) 
        {
            try
            {
                GroundObjectInstance gi = this.Find(obj);
                
                if (gi != null)
                {
                    if (obj.IsConsumed)
                    {
                        gi.RequiresRedraw = true;
                        return null;
                    }
                    gi.Data = obj;
                    gi.Body = new Rectangle(obj.Location, new Size(obj.Thickness, obj.Thickness));
                }
                else
                {
                    GroundObjectInstance gNew = new GroundObjectInstance(this, obj);
                    lock (this)
                    {
                        this.Add(gNew);
                    }
                }

                return gi;
            }
            catch (Exception exc)
            {
                Logs.WriteError(exc);
                throw;
            }
        }
        public GroundObjectInstance Find(GroundObject obj)
        {
            GroundObjectInstance retValue = null;

            var gInst = this.Where(inst => inst.Data.ID == obj.ID);
            lock (this)
            {
                if (gInst.Count() > 0)
                {
                    return gInst.First();
                }
            }
            return retValue;
        }
    }
}
